<?php

namespace App\Console\Commands;


use Aitels\Foundation\Code\ClassBuilder;
use Aitels\Foundation\Generate\ClassFileGenerator;
use Illuminate\Console\Command;
use Illuminate\Support\Str;


class GenerateModelAndValidation extends Command
{
    protected $signature = 'gen:validation';
    protected $description = '根据模型自动生成模型类、验证trait';
    protected $dontGenerate = ['AdminRule'];

    public function handle()
    {
        app()->genCommand = $this;
        $this->generateValidations();
        $this->generateModels();

    }


    public function generateModels()
    {
        $generator = new ClassFileGenerator();
        $definitions = [];
        foreach ($this->getDefinitions() as $table) {
            $modelName = $table['tableModelName'];
            $path = "Modules\\Common\\Models\\$modelName";
            $definitions[$path] = [
                'methods' => [],
                'extends' => 'BaseModel',
                'useTraits' => ["{$modelName}Validation"],
                'uses' => ["Modules\\Common\\Models\\Validation\\{$modelName}Validation"]
            ];
        }
        $generator->generateByDefinitions($definitions);
    }


    public function generateValidations()
    {
        $generator = new ClassFileGenerator();
        $definitions = [];
        foreach ($this->getDefinitions() as $table) {
            $modelName = $table['tableModelName'];
            $path = "Modules\\Common\\Models\\Validation\\{$modelName}Validation";

            $docs = $this->buildPropertyDocs($table);
            $code = $this->buildRule($table);

            list($createCode, $updateCode) = $this->buildRule($table);

            $definitions[$path] = [
                'docs' => $docs,
                'methods' => [
                    'createRules' => [
                        'code' => $createCode,
                        'modifier' => ClassBuilder::PUBLIC,
                        'comments' => []
                    ],
                    'updateRules' => [
                        'code' => $updateCode,
                        'modifier' => ClassBuilder::PUBLIC,
                        'comments' => []
                    ],
                ],
            ];
        }
        $generator->generateTraitFilesByDefinitions($definitions, true);
    }

    public function buildPropertyDocs($table)
    {
        $docs = [];
        foreach ($table['columns'] as $column) {
            if (Str::contains(strtolower($column['type']), ['integer', 'increments', 'decimal'])) {
                $docs[] = '@property int $' . $column['name'];
            } elseif (Str::contains(strtolower($column['type']), ['double', 'float'])) {
                $docs[] = '@property float $' . $column['name'];
            } else {
                $docs[] = '@property string $' . $column['name'];
            }
        }
        return $docs;
    }


    public function buildRule($table)
    {
        $template = <<<CODE
 return [
            'rules' => [
                %
            ],
            'messages' => [
            ],
            'customAttributes' => [
            ]
        ];
CODE;
        $updateRule = '';
        $createRule = '';
        foreach ($table['columns'] as $column) {
            if (in_array($column['name'],
                ['id', 'created_at', 'updated_at', 'deleted_at', 'password', 'token', 'token_expired_at'])) {
                continue;
            }

            $updateConstraint = '';
            $createConstraint = 'required';

            if ($column['type'] === 'string') {
                $createConstraint .= '|between:0,' . $column['param1'];
                $updateConstraint .= '|between:0, ' . $column['param1'];
            }

            if (Str::contains(Str::lower($column['type']), 'integer')) {
                $createConstraint .= '|integer';
                $updateConstraint .= '|integer';
            }

            if ($column['type'] === 'tinyInteger') {
                if (preg_match_all('/([0-9]+)\s*[：:]\s*[\x{4e00}-\x{9fa5}]+/u', $column['comment'], $match) > 0) {
                    $dict = implode(',', $match[1]);
                    if (!Str::contains($dict, '0,')) {
                        $dict = '0,' . $dict;
                    }
                    $createConstraint .= '|in:' . $dict;
                    $updateConstraint .= '|in:' . $dict;
                }
            }

            if ($column['type'] === 'timestamp') {
                $createConstraint .= '|date_format:Y-m-d H:i:s';
                $updateConstraint .= '|date_format:Y-m-d H:i:s';
            }

            if ($column['type'] === 'date') {
                $createConstraint .= '|date_format:Y-m-d';
                $updateConstraint .= '|date_format:Y-m-d';
            }

            if ($column['type'] === 'decimal') {
                if ($column['param2'] == 2) {
                    $createConstraint .= '|decimal2d';
                    $updateConstraint .= '|decimal2d';
                } elseif ($column['param2'] == 1) {
                    $createConstraint .= '|decimal1d';
                    $updateConstraint .= '|decimal1d';
                }
            }

            if (Str::contains($column['name'], 'mobile')) {
                $createConstraint .= '|mobile';
                $updateConstraint .= '|mobile';
            }

            if (Str::contains($column['name'], 'email')) {
                $createConstraint .= '|email:rfc';
                $updateConstraint .= '|email:rfc';
            }

            if (Str::startsWith($column['index'], ['unique', 'unique-soft'])) {
                if (Str::contains($column['index'], ',')) {
                    $createConstraint .= '|union_unique:' . $table['tableName'] . ',' . Str::after($column['index'], ':');
                    $updateConstraint .= '|union_unique:' . $table['tableName'] . ',' . Str::after($column['index'], ':');
                } else {
                    $createConstraint .= '|single_unique:' . $table['tableName'] . ',' . $column['name'];
                    $updateConstraint .= '|single_unique:' . $table['tableName'] . ',' . $column['name'];
                }
            }


            $updateConstraint = ltrim($updateConstraint, '|');

            $createRule .= "'{$column['name']}'=>'{$createConstraint}'," . PHP_EOL . '                ';
            $updateRule .= "'{$column['name']}'=>'{$updateConstraint}'," . PHP_EOL . '                ';
        }
        $createTemplate = str_replace('%', $createRule, $template);
        $updateTemplate = str_replace('%', $updateRule, $template);

        return [rtrim($createTemplate), rtrim($updateTemplate)];
    }


    protected function getDefinitions()
    {
        //根据design留下来的数据库设计信息获取系统中的模型
        $databaseDefinitions = require storage_path('design/cache.php');
//        $databaseDefinitions = collect($databaseDefinitions)->take(1)->all();
        return $databaseDefinitions;
    }


}
